﻿using System;
using Tiny.Imaging.Filter.PixelLibrary;
using Tiny.Imaging.Filter.ChannelBlendLibrary;

namespace Tiny.Imaging.Filter.BaseFilter
{
    public abstract class BaseFilter : IPointFilter
    {
        protected Func<int, int, int> BlendFunc { get; set; }
        protected int Opacity { get; set; }

        protected BaseFilter(Func<int, int, int> blend = null, int opacity = 100)
        {
            BlendFunc = blend ?? ChannelBlend.Normal;
            Opacity = opacity;
        }

        #region IPointFilter Members

        public virtual int[] Apply(int[] pixels)
        {
            var results = new int[pixels.Length];
            for (int i = 0; i < pixels.Length; ++i)
            {
                results[i] = Process(Rgba.Parse(pixels[i]));
            }

            return results;
        }

        #endregion

        public abstract int Process(Rgba pixel);

        protected Rgba BlendRgba(Rgba baseRgba, Rgba blendRgba)
        {
            return new Rgba
                       {
                           R = Blend(baseRgba.R, blendRgba.R),
                           G = Blend(baseRgba.G, blendRgba.G),
                           B = Blend(baseRgba.B, blendRgba.B),
                           A = baseRgba.A
                       };
        }

        protected int Blend(int baseColor, int blendColor)
        {
            if (baseColor < 0 || baseColor > 256)
            {
                throw new ArgumentOutOfRangeException("baseColor");
            }

            if (blendColor < 0 || blendColor > 256)
            {
                throw new ArgumentOutOfRangeException("blendColor");
            }

            return Opacity < 100
                       ? ChannelBlend.AlphaFunc(baseColor, blendColor, BlendFunc, Opacity)
                       : BlendFunc(baseColor, blendColor);
        }
    }
}